using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Toenda.Foundation.Drawing {
	/// <summary>
	/// Class ImageGenerator
	/// </summary>
	public class ImageGenerator {
		#region "NESTED TYPES"
		// ---------------------------------------------------
		// NESTED TYPES
		// ---------------------------------------------------
		#endregion

		#region "INTERNAL VARIABLES"
		// ---------------------------------------------------
		// INTERNAL VARIABLES
		// ---------------------------------------------------
		#endregion

		#region "CONSTRUCTORS"
		// ---------------------------------------------------
		// CONSTRUCTORS
		// ---------------------------------------------------

		/// <summary>
		/// Default constructor
		/// </summary>
		public ImageGenerator() {
		}

		#endregion

		#region "INTERFACE IMPLEMENTATIONS"
		// ---------------------------------------------------
		// INTERFACE IMPLEMENTATIONS
		// ---------------------------------------------------
		#endregion

		#region "PROPERTIES"
		// ---------------------------------------------------
		// PROPERTIES
		// ---------------------------------------------------
		#endregion

		#region "EVENTS"
		// ---------------------------------------------------
		// EVENTS
		// ---------------------------------------------------
		#endregion

		#region "PRIVATE MEMBERS"
		// ---------------------------------------------------
		// PRIVATE MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Texts the size.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="font">The font.</param>
		/// <param name="width">The width.</param>
		/// <param name="height">The height.</param>
		private void TextSize(string text, Font font, out int width, out int height) {
			Size objSize = TextRenderer.MeasureText(text, font);
			width = objSize.Width;
			height = objSize.Height;
		}

		#endregion

		#region "PROTECTED MEMBERS"
		// ---------------------------------------------------
		// PROTECTED MEMBERS
		// ---------------------------------------------------
		#endregion

		#region "PUBLIC MEMBERS"
		// ---------------------------------------------------
		// PUBLIC MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Generate a new image with a specific resolution
		/// </summary>
		/// <param name="image">The image.</param>
		/// <param name="width">The width.</param>
		/// <returns>A Image</returns>
		/// <exception>If image is null.</exception>
		public Bitmap GenerateNewResolution(Bitmap image, int width) {
			return GenerateNewResolution(image, width, -1);
		}

		/// <summary>
		/// Generates the new resolution.
		/// </summary>
		/// <param name="image">The image.</param>
		/// <param name="width">The width.</param>
		/// <param name="height">The height.</param>
		/// <returns></returns>
		/// <exception>If image is null.</exception>
		public Bitmap GenerateNewResolution(Bitmap image, int width, int height) {
			if(image == null) {
				throw new ArgumentNullException("image", "The parameter cannot be null!");
			}

			Bitmap sourceImage = image;
			int w = 0, h = 0;
			double prop = 0;

			if(image.Width > width) {
				// compute proportation
				prop = (double)image.Width / (double)image.Height;

				w = width;
				h = ( height < 1 ? (int)System.Math.Round(width / prop, 0) : height );

				// -- interpolation

				//Bitmap sourceImage = uploadedImage;
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}

				sourceImage.Dispose();
				sourceImage = targetImage;
			}
			else {
				width = image.Width;
				height = image.Height;
				Bitmap targetImage = new Bitmap(width, height);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}

				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generates the bitmap with text.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="font">The font.</param>
		/// <param name="foreColor">Color of the fore.</param>
		/// <param name="backColor">Color of the back.</param>
		/// <returns></returns>
		public Image GenerateBitmapWithText(string text, Font font, Color foreColor, Color backColor) {
			return GenerateBitmapWithText(text, font, foreColor, backColor, -1, -1);
		}

		/// <summary>
		/// Generates the bitmap with text.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="font">The font.</param>
		/// <param name="foreColor">Color of the fore.</param>
		/// <param name="backColor">Color of the back.</param>
		/// <param name="width">The width.</param>
		/// <param name="height">The height.</param>
		/// <returns></returns>
		public Image GenerateBitmapWithText(string text, Font font, Color foreColor, Color backColor, int width, int height) {
			int intWidth, intHeight;

			TextSize(text, font, out intWidth, out intHeight);

			SolidBrush objBrushForeColor = new SolidBrush(foreColor);
			SolidBrush objBrushBackColor = new SolidBrush(backColor);

			Point objPoint = new Point(5, 5);

			Bitmap objBitmap = new Bitmap(( width > 0 ? width : intWidth ), ( height > 0 ? height : intHeight ));
			Graphics objGraphics = Graphics.FromImage(objBitmap);

			objGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
			objGraphics.FillRectangle(objBrushBackColor, 0, 0, ( width > 0 ? width : intWidth ), ( height > 0 ? height : intHeight ));
			//objGraphics.FillRectangle(objBrushBackColor, 10, 10, intWidth, intHeight);
			objGraphics.DrawString(text, font, objBrushForeColor, objPoint);

			return objBitmap;
		}


		/// <summary>
		/// Generate a new image with a resolution of 1024 x XXX
		/// </summary>
		/// <param name="uploadedImage">The uploaded image.</param>
		/// <returns>A Image</returns>
		/// <exception>If image is null.</exception>
		public Bitmap Generate1024Pixel(Bitmap uploadedImage) {
			//if(image == null)
			//    throw new ArgumentNullException("image");

			//Bitmap bmp = null;
			//int x = 0, y = 0;
			//double prop = 0;

			//if(image.Width > 1024) {
			//    // compute proportation
			//    prop = (double)image.Width / (double)image.Height;

			//    x = 1024;
			//    y = (int)System.Math.Round(1024 / prop, 0);

			//    bmp = new Bitmap((Image)image, new Size(x, y));
			//}
			//else {
			//    bmp = new Bitmap((Image)image);
			//}

			//return bmp;
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			double prop = 0;

			if(uploadedImage.Width > 1024) {
				// compute proportation
				prop = (double)uploadedImage.Width / (double)uploadedImage.Height;

				w = 1024;
				h = (int)System.Math.Round(1024 / prop, 0);

				// -- interpolation

				//Bitmap sourceImage = uploadedImage;
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}

				// --

				//bmp = new Bitmap((Image)image, new Size(x, y));
				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generate a new image with a resolution of 500 x XXX
		/// </summary>
		/// <param name="uploadedImage">The image.</param>
		/// <returns></returns>
		/// <exception>If uploadedImage is null.</exception>
		public Bitmap Generate500Pixel(Bitmap uploadedImage) {
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			double prop = 0;

			if(uploadedImage.Width > 500) {
				// compute proportation
				prop = (double)uploadedImage.Width / (double)uploadedImage.Height;

				w = 500;
				h = (int)System.Math.Round(500 / prop, 0);

				// -- interpolation

				//Bitmap sourceImage = uploadedImage;
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}

				// --

				//bmp = new Bitmap((Image)image, new Size(x, y));
				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generate a new image with a resolution of 240 x XXX
		/// </summary>
		/// <param name="uploadedImage">The image.</param>
		/// <returns></returns>
		/// <exception>If uploadedImage is null.</exception>
		public Bitmap Generate240Pixel(Bitmap uploadedImage) {
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			double prop = 0;

			if(uploadedImage.Width > 240) {
				// compute proportation
				prop = (double)uploadedImage.Width / (double)uploadedImage.Height;

				w = 240;
				h = (int)System.Math.Round(240 / prop, 0);

				// -- interpolation

				//Bitmap sourceImage = uploadedImage;
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}
				
				//

				//bmp = new Bitmap((Image)image, new Size(x, y));
				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generate a new image with a resolution of 100 x XXX
		/// </summary>
		/// <param name="uploadedImage">The image.</param>
		/// <returns></returns>
		/// <exception>If uploadedImage is null.</exception>
		public Bitmap Generate100Pixel(Bitmap uploadedImage) {
			//if(image == null)
			//    throw new ArgumentNullException("image");

			//Bitmap bmp = null;
			//int x = 0, y = 0;
			//double prop = 0;

			//if(image.Width > 100) {
			//    // compute proportation
			//    prop = (double)image.Width / (double)image.Height;

			//    if(image.Width > image.Height) {
			//        x = 100;
			//        y = (int)System.Math.Round(100 / prop, 0);
			//    }
			//    else {
			//        x = (int)System.Math.Round(100 * prop, 0);
			//        y = 100;
			//    }

			//    bmp = new Bitmap((Image)image, new Size(x, y));
			//}
			//else {
			//    bmp = new Bitmap((Image)image);
			//}

			//return bmp;
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			double prop = 0;

			if(uploadedImage.Width > 1024) {
				// compute proportation
				prop = (double)uploadedImage.Width / (double)uploadedImage.Height;

				//w = 100;
				//h = (int)System.Math.Round(100 / prop, 0);

				if(uploadedImage.Width > uploadedImage.Height) {
					w = 100;
					h = (int)System.Math.Round(100 / prop, 0);
				}
				else {
					w = (int)System.Math.Round(100 * prop, 0);
					h = 100;
				}

				// -- interpolation

				//Bitmap sourceImage = uploadedImage;
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;

					using(ImageAttributes ia = new ImageAttributes()) {
						ia.SetWrapMode(WrapMode.TileFlipXY);
						g.InterpolationMode = InterpolationMode.HighQualityBicubic;
						g.DrawImage(
							(Image)sourceImage,
							new Rectangle(0, 0, w, h),
							0,
							0,
							(float)sourceImage.Width,
							(float)sourceImage.Height,
							GraphicsUnit.Pixel,
							ia
						);
					}
				}

				// --

				//bmp = new Bitmap((Image)image, new Size(x, y));
				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generate a new image with a resolution of 75x75 x XXX
		/// </summary>
		/// <param name="uploadedImage">The image.</param>
		/// <returns></returns>
		/// <exception>If uploadedImage is null.</exception>
		public Bitmap Generate75x75Pixel(Bitmap uploadedImage) {
			//if(image == null)
			//    throw new ArgumentNullException("image");

			//Bitmap bmp = null;
			//Bitmap crapped = null;
			//int x = 0, y = 0;
			//double prop = 0;

			//if(image.Width > 75) {
			//    // compute proportation
			//    prop = (double)image.Width / (double)image.Height;

			//    if(image.Width > image.Height) {
			//        x = (int)System.Math.Round(75 * prop, 0);
			//        y = 75;
			//    }
			//    else {
			//        x = 75;
			//        y = (int)System.Math.Round(75 / prop, 0);
			//    }

			//    bmp = new Bitmap((Image)image, new Size(x, y));

			//    crapped = new Bitmap(75, 75);
			//    Graphics g = Graphics.FromImage(crapped);
			//    g.DrawImage(bmp, 
			//        new Rectangle(0, 0, 75, 75), 
			//        new Rectangle(0, 0, 75, 75), 
			//        GraphicsUnit.Pixel
			//    );

			//    bmp = crapped;
			//}
			//else {
			//    bmp = image;
			//}

			//return bmp;
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			double prop = 0;

			if(uploadedImage.Width > 75) {
				// compute proportation
				prop = (double)uploadedImage.Width / (double)uploadedImage.Height;

				if(uploadedImage.Width > uploadedImage.Height) {
					w = (int)System.Math.Round(75 * prop, 0);
					h = 75;
				}
				else {
					w = 75;
					h = (int)System.Math.Round(75 / prop, 0);
				}

				// -- interpolation to 75pixels

				Bitmap tmpImage = new Bitmap(w, h);

				// top position
				int x = 0; // left -> right
				int y = 0; // top -> bottom

				if(w > h) {
					x = (w - h) / 2;
					y = 0;

					x = x * ( -1 );
				}
				else {
					x = 0;
					y = ( h - w ) / 2;

					y = y * ( -1 );
				}

				using(Graphics g = Graphics.FromImage((Image)tmpImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;
					g.InterpolationMode = InterpolationMode.HighQualityBicubic;

					g.DrawImage(
						(Image)sourceImage,
						new Rectangle(x, y, w, h),
						new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
						GraphicsUnit.Pixel
					);
				}

				// -- interpolation

				Bitmap targetImage = new Bitmap(75, 75);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;
					g.InterpolationMode = InterpolationMode.HighQualityBicubic;
					g.DrawImage(
						(Image)tmpImage,
						new Rectangle(0, 0, 75, 75),
						0,
						0,
						75,
						75,
						GraphicsUnit.Pixel
					);
				}

				// --

				tmpImage.Dispose();
				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		/// <summary>
		/// Generate a new image with a format of 4:3
		/// </summary>
		/// <param name="uploadedImage">The image.</param>
		/// <returns></returns>
		/// <exception>If uploadedImage is null.</exception>
		public Bitmap Generate4to3Format(Bitmap uploadedImage) {
			if(uploadedImage == null) {
				throw new ArgumentNullException("uploadedImage");
			}

			Bitmap sourceImage = uploadedImage;
			int w = 0, h = 0;
			int prop = 0;
			const decimal MULTI = 1.3333333333333333333333333333333m;

			int posX = 0;
			int posY = 0;

			decimal prop0 = System.Math.Round(MULTI, 28);
			decimal prop1 = 0;

			bool canConvert = true;

			if(uploadedImage.Width < uploadedImage.Height) {
				prop1 = System.Math.Round(
					Convert.ToDecimal(
						Convert.ToDecimal(uploadedImage.Height) / Convert.ToDecimal(uploadedImage.Width)
					),
					28
				);

				if(prop1 == prop0) {
					canConvert = false;
				}

				if(canConvert) {
					w = uploadedImage.Width;
					h = Convert.ToInt32(
						System.Math.Round(
							Convert.ToDecimal(
								Convert.ToDecimal(w) * MULTI
							),
							0
						)
					);

					prop = uploadedImage.Height - h;

					//posY = Convert.ToInt32(System.Math.Round(Convert.ToDecimal(prop / 2), 0)) - prop;
					posY = Convert.ToInt32(System.Math.Round(Convert.ToDecimal(prop / 2), 0));
				}
			}
			else {
				prop1 = System.Math.Round(
					Convert.ToDecimal(
						Convert.ToDecimal(uploadedImage.Width) / Convert.ToDecimal(uploadedImage.Height)
					),
					28
				);

				if(prop1 == prop0) {
					canConvert = false;
				}

				if(canConvert) {
					h = uploadedImage.Height;
					w = Convert.ToInt32(
						System.Math.Round(
							Convert.ToDecimal(
								Convert.ToDecimal(h) * MULTI
							),
							0
						)
					);

					prop = uploadedImage.Width - w;

					//posX = Convert.ToInt32(System.Math.Round(Convert.ToDecimal(prop / 2), 0)) - prop;
					posX = Convert.ToInt32(System.Math.Round(Convert.ToDecimal(prop / 2), 0));
				}
			}

			// -- interpolation to 4:3 format

			if(canConvert) {
				Bitmap targetImage = new Bitmap(w, h);

				using(Graphics g = Graphics.FromImage((Image)targetImage)) {
					g.PixelOffsetMode = PixelOffsetMode.HighQuality;
					g.InterpolationMode = InterpolationMode.HighQualityBicubic;

					g.DrawImage(
						(Image)sourceImage,
						new Rectangle(0, 0, w, h),
						posX,
						posY,
						sourceImage.Width,
						( sourceImage.Height - prop ),
						GraphicsUnit.Pixel
					);
				}

				// --

				sourceImage.Dispose();
				sourceImage = targetImage;
			}

			return sourceImage;
		}

		#endregion
	}
}
